(** Environments (implemented with hashtables) and operations on them 
@author Johannes Woolard
*)

(** The type of Environments (ie. Heirarchical maps). *)
type ('a, 'b) env = { 
    e_elems : ('a, 'b) Hashtbl.t ref;    (** Contents of the environment *)
    e_parent : (('a, 'b) env) option;   (** The parent of this environment *)
};;

(** Create a new environment, with a given parent. *)
val new_env : ('a, 'b) env -> ('a, 'b)  env;;

(** Get an empty environment with no parent *)
val empty_env : unit -> ('a, 'b) env;;

(** [bind_env e k v] binds the value [v] to the variable [k] in the current Environment (as opposed to any parent environment) *)
val bind_env : ('a, 'b) env -> 'a -> 'b -> unit;;

(** Tests if a variable name is bound in the current or any parent environment *)
val exists_env : ('a, 'b) env -> 'a -> bool;;

(** Gets the value of a variable from the environment or its parents 
@raise Not_found If the specified variable isn't found.
*)
val get_env : ('a, 'b) env -> 'a -> 'b;;

(** Gets the contents of the top level of the environment as a hashtable *)
val get_hashtbl : ('a, 'b) env -> ('a, 'b) Hashtbl.t ref;;